----------------------------------------------------------------------
   ----------------------------------------------------------------------
   DOCUMENT:
                     PROGRAMMING DMA I/O WITH VMDMA
                               Version 1.0
                              March 8, 1991

               Programming and Documentation by Ryan Hanlon
           Copyright (c) 1991,  Covox, Inc.  All Rights Reserved
   ----------------------------------------------------------------------
   GENERAL DESCRIPTION 
       
       The recording and playback of non-compressed 8 bit PCM sound
       data via DMA (memory to port, port to memory), can be achieved
       by setting the Voice Master card and mother board DMA controller
       properly. This document will supply all of the raw information
       you will need to write recording and playback software for the
       Voice Master and the Sound Master II boards.
       
       The Voice Master is only capable of being set to use IRQ 3 or IRQ 7 
       while the Sound Master II board can use any one of IRQ's 3 through 7. 
       Both the Voice Master and the Sound Master II were designed to use
       DMA channel 1 or channel 3 and one of the port ranges starting at
       0x0220, 0x0240, 0x0280, or 0x02C0.

       NOTE : Except for the IRQ changes on the Sound Master II the 
       functionality of the Voice Master is replicated on the Sound 
       Master II board. For the duration of this document all references
       to the Voice Master (VMDMA), apply equally to the Sound Master II
       board. 

       This document should be used in conjunction with the document and
       source code supplied with the program sm2detec.exe.

   ----------------------------------------------------------------------
   VOICE MASTER PORTS

     BASE PORTS
       Jumper setting positions 1 through 4 determine the BASE PORT of
       the Voice Master.  

       0x0220 to 0x022F,
       0x0240 to 0x024F,
       0x0280 to 0x028F,
       0x02C0 to 0x02CF    

     BASE PORT OFFSETS
       The BASE PORT plus (+) the BASE PORT OFFSET can be used to access the
       ports on the Voice Master.  As can be seen below only port offsets
       from 0x08 and 0x0F are used on the Voice Master.
 
       8254 TIMER 0 OFFSET   =   0x08   Timer/Clock
       8254 TIMER 1 OFFSET   =   0x09   Timer/Clock
       8254 TIMER 2 OFFSET   =   0x0A   Timer/Clock
       8254 CONTROL OFFSET   =   0x0B   Timer/Clock control register

       CLEAR IRQ OFFSET      =   0x0C   \
       DISABLE VMDMA OFFSET  =   0x0D    > VMDMA Control ports
       ENABLE VMDMA OFFSET   =   0x0E   /

       DAC OFFSET            =   0x0F   The DAC OFFSET port should
                                         not be written to during DMA
                                         i/o.
   ----------------------------------------------------------------------
   VMDMA CONTROL PORT OFFSETS

     DISABLE DMA OFFSET   =   0x0D
       Writing to this port will disable DREQ (DMA Request), channel 1
       or DREQ channel 3 thus preventing all VMDMA i/o.


     ENABLE DMA OFFSET    =   0x0E
       Writing to this port should be done last and only after all clock and
       DMA setup has been completed.  A write to this port will fire off 
       a DREQ (cause the DREQ line to go low), thus allowing the VMDMA i/o
       to begin.


     CLEAR IRQ OFFSET      =   0x0C
       This BASE PORT offset is to be utilized after every DMA
       terminal count is reached.  It is common to find this port
       being written to inside an interrupt handler.  Any value
       may be output to the port.

    ----------------------------------------------------------------------
   INTEL 8254 COUNTER/TIMER ONBOARD THE VOICE MASTER
   
     The Voice Master is equipped with the Intel 8254 programmable interval
     counter/timer. COUNTER 2 is used for DMA i/o control.  COUNTER 1 and 3
     are not used by the Voice Master and are available for general purpose
     use within software.

     TIMER 0 OFFSET = 0x08    TIMER 1 OFFSET = 0x09    TIMER 2 OFFSET = 0x0A    

     8254 CONTROL OFFSET = 0x0B

     COUNTER 2 is setup to fire off DREQ's at given intervals by
     latching to the 8254 CONTROL OFFSET port in LSB/MSB order.
     The formula you will need to properly program this DREQ
     frequency is shown below.

                        7.1MHz
         i/o rate  =  ------------   where N is a 16 bit divisor that
                          N          is written, 8 bits at a time,
                                     to one of the TIMER OFFSETs.
                           
     Each DREQ sent by the Voice Master is received by the 8237 DMA
     controller on the mother board.  After one 8 bit DMA read or write is
     performed the 8237 sends a DACK (DMA Acknowledged), signal to the Voice
     Master board.  This DACK signal effectively disables the Voice Master
     from sending another DREQ to the 8237 until CLOCK 2 reaches zero again.
         
     Bit settings for the CONTROL port of the 8254.  
       
      bits 7,6 =  00 timer 0    bits 5,4 = 00 latch preset
                  01 timer 1               01 read/write only MSB
                  10 timer 2               10 read/write only LSB
                                           01 read/write LSB, then MSB

      bits 3,1 = 000 mode 0     bit    0 =  0 binary
                 001 mode 1                 1 BCD decrementing
                 010 mode 2
                 011 mode 3
                 100 mode 4
                 101 mode 5

  ----------------------------------------------------------------------
   8237 DMA CONTROLLER ON THE MOTHERBOARD

     The DMA on the mother board should be completely setup for i/o
     only after the Voice Master board has had the DREQ lines
     disabled. (See DISABLE VMDMA OFFSET for more information).

     The recommended settings for performing recording or playback 
     are as follows : 
         1. single mode
         2. address increment
         3. no automatic reinitialize
         4. read or write (depending on desired results)
         5. channel 1 or 3 (depending on jumper setting on Voice Master)

     Bit settings for the control byte of the 8237.  
        bits 7,6 = 00 demand mode
                   01 single mode 
                   10 block mode
                   11 cascade mode
                   
        bit  5   =  0 address increment
                    1 address decrement

        bit  4   =  0 no automatic reinitialize
                    1 automatic reinitialize
                    
        bits 3,2 = 00 verify
                   01 write
                   10 read

        bits 1,0 = 00 channel 0
                   01 channel 1
                   10 channel 2
                   11 channel 3
      

   ----------------------------------------------------------------------

   DMA BUFFER - 20-BIT SEGMENT ADDRESS

   Bits 2 and 3 of the byte written to the 8237 DMA CONTROLLER determine
   whether DMA recording or playback will be performed.  Both DMA i/o
   directions require that the start address of a data buffer be output
   to the DMA ADDRESS REGISTER and the physical page be outp to the 
   DMA PAGE REGISTER.


   EXAMPLE : 
   
   This example uses a long named temp_address to store the 20 bit 
   address of a Test_Buffer of char.  First the page address of Test_Buffer
   is outp to the DMA PAGE REGISTER.  The remaining 16 bit address
   is outp to the DMA ADDR REGISTER.  Channel 1 is the active settings
   of the Voice Master for this example.

   /* Get 20 bit address of test buffer
   */
   temp_address = ((long)FP_SEG(Test_Buffer))<<4) + (long)FP_OFF(Test_Buffer);

 
   /* Output segment page address of test buffer to the DMA PAGE REGISTER
   // for channel 1.
   */
   outp( DMA_CH1_PAGE_REGISTER, (unsigned char)(temp_address >> 16) );

     
   /* Set the address of the test buffer.  outp LSB then MSB.
   */
   outp( DMA_CLEAR_LSB_MSB, 0x00 );
   outp( DMA_CH1_ADDR_REGISTER, (unsigned char)(temp_address) );
   outp( DMA_CH1_ADDR_REGISTER, (unsigned char)(temp_address >> 8) );

   ----------------------------------------------------------------------

   DMA BUFFER - CURRENT BUFFER SIZE

   The size of the current buffer being used with DMA i/o should be
   output to the DMA COUNT REGISTER.  Special considerations need to be
   made for buffers that  cross page boundaries.
   

   EXAMPLE : 

   This example assumes that the length of Test_Buffer is stored in a
   variable named Test_Buffer_Count. Since the DMA predecrements this
   count before a byte is processed we add 1 to the count before it
   is outp to the DMA COUNT REGISTER.  Channel 1 is the active settings
   of the Voice Master for this example.
   This example does not check to see if the length of the buffer exceeds
   the available length left before the page boundary. 

      /* Set word count on DMA channel 1.
      */ 
      outp( DMA_CLEAR_LSB_MSB, 0x00 );
      outp( DMA_CH1_COUNT_REGISTER, Test_Buffer_Count + 1 );
      outp( DMA_CH1_COUNT_REGISTER, 0x00 );

      /* Enable 8237 DMA on the mother board
      */
      outp( DMA_MASK_REGISTER , DMA_CH1);


   ----------------------------------------------------------------------

   IMPORTANT PROGRAMMING CONSIDERATIONS

   1. Disabling and enabling of the DMA subsystem can cause an IRQ to fire
      off.

   2. When the terminal count is reached on the 8237 DMA controller the
      DACK line on the Voice Master goes high.  To set this line to 
      low and thus allow the next interrupt to occur you must
      outp( (vmdma_base_port + VMDMA_CLEAR_IRQ_OFFSET), 0) directly before
      issuing an  outp(0x20,0x20) in your interrupt handler.